//初始化头文件
#include <linux/init.h>	
//最基本的文件，支持动态添加和卸载模块。		   
#include <linux/module.h>
//平台设备所需要的头文件 		  
#include <linux/platform_device.h> 
#include <linux/ioport.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
//文件系统头文件，定义文件表结构（file,buffer_head,m_inode等）
#include <linux/fs.h>	
//包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义。	 
#include <linux/uaccess.h>	 
//包含了ioremap、iowrite等内核访问IO内存等函数的定义。
#include <linux/io.h>	


#define DEVICE_NAME "led_driver"
#define BUF_SIZE 100

static char device_buffer[BUF_SIZE] = "Hello, Misc Device!\n";
static volatile unsigned int *vir_gpio5_dr = NULL;
static volatile unsigned int *vir_gpio1_dr = NULL;
struct resource *led_mem;
struct resource *led_mem2;

// 设备打开函数
static int misc_open(struct inode *inode, struct file *file)
{
    pr_info("misc_device: opened\n");
    return 0;
}

// 设备关闭函数
static int misc_close(struct inode *inode, struct file *file)
{
    pr_info("misc_device: closed\n");
    return 0;
}

// 设备读函数
static ssize_t misc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    size_t len = strlen(device_buffer);

    if (*ppos >= len)
        return 0; // 已经读取完

    if (count > len - *ppos)
        count = len - *ppos;

    if (copy_to_user(buf, device_buffer + *ppos, count))
        return -EFAULT;

    *ppos += count;
    return 0;
}

// 设备写函数
static ssize_t misc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    if (count > BUF_SIZE - 1)
        return -EINVAL; // 缓冲区溢出

    if (copy_from_user(device_buffer, buf, count))
        return -EFAULT;
    if(vir_gpio5_dr == NULL)
    {
        pr_info("vir_gpio5_dr == NULL\n");
        return -EFAULT;
    }
    device_buffer[count] = '\0'; // 添加字符串结束符
    pr_info("misc_device: received %s\n", device_buffer);

    //led 亮灭控制
    pr_info("device_buffer[0] =  %c\n", device_buffer[0]);
    pr_info("device_buffer[1] =  %c\n", device_buffer[1]);

    switch(device_buffer[1])
    {
        case '0':
        {
            if(device_buffer[0] == 'o')
            {
                pr_info("LED %c  ON! \n", device_buffer[1]);
                *vir_gpio5_dr &= ~(1<<3);
            }
            else
            {
                pr_info("LED %c  OFF! \n", device_buffer[1]);
                *vir_gpio5_dr |= (1<<3);
            }
            break;
        }
         case '1':
        {
            if(device_buffer[0] == 'o')
            {
                pr_info("LED %c  ON! \n", device_buffer[1]);
                *vir_gpio1_dr &= ~(1<<3);
            }
            else
            {
                pr_info("LED %c  OFF! \n", device_buffer[1]);
                *vir_gpio1_dr |= (1<<3);
            }
            break;
        }
        case '2':
        {
            if(device_buffer[0]  == 'o')
            {
                pr_info("LED %c  ON! \n", device_buffer[1]);
                *vir_gpio1_dr &= ~(1<<5);
            }
            else
            {
                pr_info("LED %c  OFF! \n", device_buffer[1]);
                *vir_gpio1_dr |= (1<<5);
            }
            break;
        }
        case '3':
        {
            if(device_buffer[0] == 'o')
            {
                pr_info("LED %c  ON! \n", device_buffer[1]);
                *vir_gpio1_dr &= ~(1<<6);
            }
            else
            {
                pr_info("LED %c  OFF! \n", device_buffer[1]);
                *vir_gpio1_dr |= (1<<6);
            }
            break;
        }
    }

    return count;
}

// 文件操作结构体
static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = misc_open,
    .release = misc_close,
    .read = misc_read,
    .write = misc_write,
};

// 杂项设备结构体
static struct miscdevice misc_dev = {
    .minor = MISC_DYNAMIC_MINOR, // 随机分配子设备号
    .name = DEVICE_NAME,
    .fops = &fops,
};


/****************************************************************************************
 * @brief led_probe : 与设备信息层（device.c）匹配成功后自动执行此函数，
 * @param inode : 文件索引
 * @param file  : 文件
 * @return 成功返回 0 	    	
 ****************************************************************************************/
int led_probe(struct platform_device *pdev)
{
    int ret;
	printk("led_probe\n");
	led_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    
	if (led_mem == NULL)
	{
		printk("platform_get_resource is error\n");
		return -EBUSY;
	}
	printk("led_res start is 0x%llx \n", led_mem->start);
	printk("led_res end is 0x%llx \n", led_mem->end);

    led_mem2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	if (led_mem2 == NULL)
	{
		printk("platform_get_resource is error\n");
		return -EBUSY;
	}
	printk("led_res2-4 start is 0x%llx \n", led_mem2->start);
	printk("led_res2-4 end is 0x%llx \n", led_mem2->end);
	/*****************************************************************/
	//映射GPIO资源
	vir_gpio5_dr = ioremap(led_mem->start, 4);
    vir_gpio1_dr = ioremap(led_mem2->start, 4);
	if (vir_gpio5_dr == NULL || vir_gpio1_dr == NULL)
	{
		printk("GPIO5_DR or GPIO1_DRioremap is error \n");
		return EBUSY;
	}
	printk("GPIO5_DR and GPIO1_DRioremap is ok \n");

	//注册杂项设备
	ret = misc_register(&misc_dev);
	if (ret < 0)
	{
		printk("misc registe is error \n");
	}
	printk("misc registe is succeed \n");

}
int led_remove(struct platform_device *pdev)
{
	printk("led_remove\n");
	return 0;
}

const struct platform_device_id led_idtable = {
	.name = "led_device",
};

// platform 驱动结构体
struct platform_driver led_driver = {
	.probe = led_probe,
	.remove = led_remove,
	.driver = {
		.owner = THIS_MODULE,
		.name = "led_device"
        },
	.id_table = &led_idtable

};

// 模块初始化
static int led_driver_init(void)
{
	int ret = 0;
	// platform驱动注册到 Linux 内核
	ret = platform_driver_register(&led_driver);
	if (ret < 0)
	{
		printk("platform_driver_register error \n");
	}
	printk("platform_driver_register ok \n");

	return 0;
}

// 模块卸载
static void __exit led_driver_exit(void)
{
    platform_driver_unregister(&led_driver);
	misc_deregister(&misc_dev);
	iounmap(vir_gpio5_dr);
    pr_info("misc_device: unregistered\n");
}

module_init(led_driver_init);
module_exit(led_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple misc device driver");
MODULE_VERSION("1.0");
